package org.epidroid.epidroid.news.ui;

import java.util.ArrayList;
import java.util.Collections;

import org.epidroid.epidroid.R;
import org.epidroid.epidroid.news.bdd.ReferencesOperations;
import org.epidroid.epidroid.news.engine.Group;
import org.epidroid.epidroid.news.engine.INewsService;
import org.epidroid.epidroid.news.engine.INewsServiceListener;
import org.epidroid.epidroid.news.engine.NewsService;
import org.epidroid.epidroid.news.engine.NewsServiceBinder;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;

/**
 * Activity that lists the list of available newsgroups
 * 
 * @author conrat_a
 * 
 */
public class NewsActivity extends Activity {

	public static final String LOGCAT = "news";

	private Boolean _showOnlyFavs = false;
	private ListView _listView = null;

	private ArrayList<Group> _listAll = null;
	private ArrayList<Group> _listFavs = null;
	private ServiceConnection _serviceConnection = null;
	private INewsService _service = null;
	private NewsAdapter _adapter = null;
	private ProgressDialog _progressDialog = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		_listAll = new ArrayList<Group>();
		setContentView(R.layout.news_list);
		NewsActivity.this._listView = (ListView) findViewById(R.id.news_list);
		_adapter = new NewsAdapter(NewsActivity.this, R.layout.news_item,
				_listAll);
		_listView.setAdapter(_adapter);
		
		showProgressDialog();
		bindWithNewsService();
	}

	@Override
	protected void onDestroy() {

		unbindService(_serviceConnection);

		super.onDestroy();
	}

	private void bindWithNewsService() {
		Intent intent = new Intent(this, NewsService.class);

		final INewsServiceListener listener = new INewsServiceListener() {

			@Override
			public void dataChanged(Message o) {
				onReceiveMessage(o);
			}
		};

		_serviceConnection = new ServiceConnection() {
			public void onServiceConnected(ComponentName name,
					IBinder servicebinder) {

				INewsService service = ((NewsServiceBinder) servicebinder)
						.getService();
				_service = service;

				_service.addListener(listener);
				launchConnection();
			}

			public void onServiceDisconnected(ComponentName name) {
				Log.i(NewsActivity.LOGCAT, "Service has disconnected!");
				/*
				 * TODO: handle error
				 */
			}
		};

		bindService(intent, _serviceConnection, Context.BIND_AUTO_CREATE);
	}

	private void launchConnection() {
		Thread t = new Thread() {
			@Override
			public void run() {
				_service.connect();
			}
		};
		t.start();
	}

	private void onReceiveMessage(final Message o) {
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				Log.d(LOGCAT, "Received event: " + o.what);
				switch (o.what) {
				case NewsService.EVENT_CONNECTED:
					connected();
					break;
				case NewsService.EVENT_CONNECTION_FAIL:
					connection_fail();
					break;
				case NewsService.EVENT_DISCONNECTED:
					connection_fail();
				default:
					break;
				}
			}
		});
	}

	private void connected() {
		//launchThreadGetData();
		launchThreadGetGroups();
	}

	private void connection_fail() {
		hideProgressDialog();
		showToast("Cannot connect to the server!");
	}

	public void showToast(String content) {
		Toast toast = Toast.makeText(getApplicationContext(), content,
				Toast.LENGTH_SHORT);
		toast.show();
	}

	private void launchThreadGetGroups () {
		AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
			private int errorCode = 0;
			
			private void addListToBdd() {
				ReferencesOperations groupsOpe = new ReferencesOperations(NewsActivity.this);
				groupsOpe.open();
				for (Group elt : _listAll) {
					groupsOpe.insertGroup(elt);
				}
				groupsOpe.close();
			}
			
			private void updateDisplay () {
				if ((null != _listFavs) && (_listFavs.size() > 0)) {
					_showOnlyFavs = true;
					_adapter.setItems(_listFavs);
					hideProgressDialog();
				} else if ((null != _listAll) && (_listAll.size() > 0)){
					_adapter.setItems(_listAll);
					hideProgressDialog();
				}
				NewsActivity.this._adapter.notifyDataSetChanged();
			}
			
			@Override
			protected void onProgressUpdate (Void... value) {
				updateDisplay();
			}
			
			@Override
			protected Boolean doInBackground(Void... params) {
				_listAll = _service.getListGroups();
				_listFavs = _service.getFavsGroups();
				publishProgress();
				
				ArrayList<Group> listAll = _service.updateListGroups();
				if (null == listAll) {
					Log.e(LOGCAT, "Could not retrieve the list of groups");
					errorCode = 1;
					return false;
				}
				Collections.sort(listAll);
				if (_listAll == null || listAll.size() != _listAll.size()) {
					_listAll = listAll;
					addListToBdd();
					return true;
				}
				
				Boolean res = false;
				ReferencesOperations groupsOpe = new ReferencesOperations(NewsActivity.this);
				for (int i = 0; i < _listAll.size(); i++) {
					if (!_listAll.get(i).getTitle().equals(listAll.get(i).getTitle()) || _listAll.get(i).getCount() != listAll.get(i).getCount()) {
						groupsOpe.open();
						res = true; // Something changed
					}
				}
				if (res) {
					_listAll = listAll;
					groupsOpe.close();
				}
				return res;
			}
			
			@Override
			protected void onPostExecute (Boolean res) {
				Log.d("TAG", "OnPostExecute");
				if (res) {
					updateDisplay();
				}
				else if (errorCode == 1){
					Toast.makeText(NewsActivity.this, R.string.news_group_failed, Toast.LENGTH_SHORT).show();
				}
				hideProgressDialog();
			}
		};
		task.execute();
	}
	
	private void launchThreadGetData() {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {

				NewsActivity.this.runOnUiThread(new Runnable() {
					@Override
					public void run() {

						// If we already have favorites, display only them
						if ((null != _listFavs) && (_listFavs.size() > 0)) {
							_showOnlyFavs = true;
							_adapter.setItems(_listFavs);
						} else {
							_adapter.setItems(_listAll);
						}

						NewsActivity.this._adapter.notifyDataSetChanged();
						hideProgressDialog();
					}
				});
			}

		});
		t.start();
	}

	public void onListItemClick(Group item) {
		showNewsgroup(item);
	}

	private void showNewsgroup(Group item) {
		String name = item.getTitle();
		Intent intent = new Intent(this, ListTopicsActivity.class);
		intent.putExtra("newsgroup", name);
		startActivity(intent);
	}

	private void showProgressDialog() {
		_progressDialog = ProgressDialog.show(this, "", "Retrieving data", true);
		_progressDialog.setCancelable(true);
		_progressDialog.setOnCancelListener(new OnCancelListener() {

			@Override
			public void onCancel(DialogInterface dialog) {
				// TODO
			}

		});
	}

	private void hideProgressDialog() {
		if (_progressDialog != null) {
			_progressDialog.dismiss();
			_progressDialog = null;
		}
	}

	/**
	 * Switch the display mode. There are two display modes, one in which every
	 * newsgroup is displayed and one in which only favorite ones are displayed.
	 */
	private void switchDisplayMode() {
		_showOnlyFavs = !_showOnlyFavs;

		if (_showOnlyFavs) {
			_listFavs = _service.getFavsGroups();
		}

		if (_showOnlyFavs && (_listFavs != null))
			_adapter.setItems(_listFavs);
		else
			_adapter.setItems(_listAll);

		_adapter.notifyDataSetChanged();
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		MenuItem item = menu.findItem(R.id.b_news_switch_favs);
		if (_showOnlyFavs)
			item.setTitle("Show all");
		else
			item.setTitle("Show favorites");
		return super.onPrepareOptionsMenu(menu);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.news_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.b_news_switch_favs:
			switchDisplayMode();
			break;
		default:
			break;
		}
		return true;
	}

}
